/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import org.aswing.ASColor;
import org.aswing.ASWingUtils;
import org.aswing.border.EmptyBorder;
import org.aswing.BorderLayout;
import org.aswing.FlowLayout;
import org.aswing.geom.Point;
import org.aswing.Insets;
import org.aswing.JFrame;
import org.aswing.JLabel;
import org.aswing.JPanel;
import org.aswing.JTextField;
import org.aswing.UIManager;

import com.bourre.commands.Delegate;
import com.bourre.events.EventType;

import fever.display.ModalScreen;
import fever.Fever;
import fever.utils.StringUtil;

import fvaswing.components.FvAlertResources;
import fvaswing.components.FvButton;

/**
 * Input dialog implementation.
 * 
 * <p>2 ways to use input dialog
 * <ul>
 *   <li>Use classic class instanciation :
 *   {@code 
 *     var d : FvInputDialog = new FvInputDialog();
 *     d.open( "What is your name ?", this );
 *   }
 *   </li>
 *   <li>Use <strong>Singleton</strong> design :
 *   {@code 
 *     FvInputDialog.getInstance().open( "What is your name ?", this );
 *   }
 *   </li>
 * </ul>
 * <br />Thus we can create specific input dialog or always use the singleton one.
 * 
 * <p>Take a look at {@link #open()} unique method to show how to use this 
 * component.
 * 
 * <p>Button labels are connected to the {@link fvaswing.components.FvAlertResources} 
 * localisation resources.
 * 
 * @author Romain Ecarnot
 */
class fvaswing.components.FvInputDialog
{
	//-------------------------------------------------------------------------
	// Events definition
	//-------------------------------------------------------------------------
	
	/** Event type broadcasted when user click on submit button. */
	public static var onInputResultEVENT : EventType = new EventType( 'onInputResult' );
	
	
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private static var _instance : FvInputDialog;
	
	private var _frame : JFrame;
	private var _label : JLabel;
	private var _input : JTextField;
	private var _bNullAllowed : Boolean;
	
	private var _submitButton : FvButton;
	private var _cancelButton : FvButton;
	
	private var _modal : ModalScreen;
	private var _listener; 
		
	
	//-------------------------------------------------------------------------
	// Public Properties
	//-------------------------------------------------------------------------
	
	/** Width of each button, in pixels. */
	public static var buttonWidth : Number = 60;
	
	/** Invalid textfield background. */
	public static var invalidColor : ASColor = new ASColor( 0xD70000 );
	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Returns {@link FvInputDialog} instance.
	 * 
	 * <p>Always returns the same instance.<br />
	 * Design Pattern Singleton.
	 * @return {@link FvInputDialog} instance
	 */
	public static function getInstance() : FvInputDialog
	{
		if( !_instance ) _instance = new FvInputDialog();
		return _instance;
	}
	
	/**
	 * Constructor.
	 */
	public function FvInputDialog()
	{
		_bNullAllowed = false;
		
		_configureUI();
	}	
	
	/**
	 * Opens the input dialog.
	 * 
	 * <p>Various way to open an input dialog : 
	 * <ul>
	 *  <li>FvInputDialog.getInstance().open( "What is your name ?", this,  _onResult );</li>
	 *  <li>FvInputDialog.getInstance().open( "What is your name ?", this,  _onResult, "param" );</li>
	 *  <li>FvInputDialog.getInstance().open( "What is your name ?", this );</li>
	 *  <li>FvInputDialog.getInstance().open( "What is your name ?", Delegate.create( this, _onResult ) );</li>
	 *  <li>FvInputDialog.getInstance().open( "What is your name ?", Delegate.create( this, _onResult, "param" ) );</li>
	 * </ul>
	 * 
	 * <p>If {@code f} callback is omitted, {@code listener} must have a {@link #onInputResultEVENT} 
	 * event handler.
	 * 
	 * @param label Message to indicate which type of information we wanted
	 * @param listener Listener object
	 * @param f ( optional ) listener callback to activate on result. 
	 */
	public function open( label : String, listener, f : Function ) : Void
	{
		_listener = (f) 
			? _getEventProxy.apply( this, arguments.splice(1) ) 
			: listener;
		
		_label.setText( label );
		_input.setBackground( UIManager.getColor( 'TextField.background' ) );
		
		_update();
		
		_modal.show();
		_frame.show();
	}
	
	/**
	 * Sets the input value.
	 * 
	 * @param s Input string value.
	 */
	public function setInputValue( s : String ) : Void
	{
		_input.setText( s );
	}
	
	/**
	 * Returns the input value.
	 */
	public function getInputValue(  ) : String
	{
		return _input.getText();
	}
	
	/**
	 * Sets if empty result is authorized.( default {@code false} )
	 */
	public function setAllowEmptyResult( b : Boolean ) : Void
	{
		_bNullAllowed = b;
	}
	
	/**
	 * Returns {@code true} if empty result is authorized.
	 */
	public function isEmptyAllowed(  ) : Boolean
	{
		return _bNullAllowed;
	}
	/**
	 * 
	 */
	public function setTitle( newTitle : String ) : Void
	{
		_frame.setTitle( newTitle );
	}
	
	/**
	 * 
	 */
	public function getTitle(  ) : String
	{
		return _frame.getTitle();
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	private function _configureUI() : Void
	{
		_modal = new ModalScreen(  0x000000, 0 );
		
		_frame = new JFrame( _modal.getModalTarget(), '', false );
		_frame.setResizable( false );
		_frame.setClosable( false );
		_frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
		_frame.setTitle( Fever.application.getTitle() );
		_frame.addEventListener( JFrame.ON_FOCUS_GAINED, _delegateFocus, this );
		
		_frame.getContentPane().setBorder( new EmptyBorder( null, new Insets( 5, 5, 5, 5 ) ) );
		_frame.getContentPane().setLayout( new BorderLayout( 5, 5 ) );	
		_frame.getContentPane().append( _getControlPanel(), BorderLayout.NORTH );
		_frame.getContentPane().append( _getButtonPanel(), BorderLayout.SOUTH );
	}
	
	private function _delegateFocus( target : JFrame ) : Void 
	{
		_input.requestFocus();	
	}
	
	private function _getControlPanel() : JPanel
	{
		_label = new JLabel( '', JLabel.LEFT );
		_input = new JTextField( '', 30 );
		_input.addActionListener( _checkResultBefore, this );
		
		var p : JPanel = new JPanel( new BorderLayout( 5, 5 ) );
		p.append( _label, BorderLayout.NORTH );
		p.append( _input, BorderLayout.CENTER );
		return p;	
	}
	
	private function _getButtonPanel() : JPanel
	{
		_submitButton = new FvButton( '' );
		_submitButton.setPreferredSize( buttonWidth, 22 );
		_submitButton.addActionListener( _checkResultBefore, this );
		
		_cancelButton = new FvButton( '' );
		_cancelButton.setPreferredSize( buttonWidth, 22 );
		_cancelButton.addActionListener( _handleClose, this );
		
		_updateLocalisation();
		
		var p : JPanel = new JPanel( new FlowLayout ( FlowLayout.CENTER, 10, 2 ) );
		p.append( _submitButton );
		p.append( _cancelButton );
		return p;	
	}
	
	private function _updateLocalisation() : Void
	{
		_submitButton.setText( FvAlertResources.getInstance().okLabel );
		_cancelButton.setText( FvAlertResources.getInstance().cancelLabel );	
	}
	
	private function _update() : Void
	{
		_updateLocalisation();
		_frame.revalidate();
		_frame.pack();
		
		var location : Point = ASWingUtils.getScreenCenterPosition();
		location.x -= _frame.getWidth()/2;
		location.y -= _frame.getHeight()/2;
		_frame.setLocation( location );
	}
	
	private function _checkResultBefore() : Void
	{
		var s : String = StringUtil.trim( _input.getText() );
		_input.setText( s );
		
		if ( _bNullAllowed ) 
		{
			_handleResult();
			return;
		}
		
		if( s.length )
		{
			_input.setBackground( UIManager.getColor( 'TextField.background' ) );
			_handleResult();
		}
		else
		{
			_input.setBackground( invalidColor );	
		}
	}
	
	private function _handleResult( ) : Void
	{
		var type : String = typeof( _listener );
		if ( type == 'object' || type == 'movieclip' )  
			_listener[ String( onInputResultEVENT ) ]( _input.getText() );
		else _listener.apply( this, [ _input.getText() ] );
		
		_handleClose();
	}
	
	private function _handleClose( ) : Void
	{
		_listener = null;
		_modal.hide();
		_frame.tryToClose();
	}
	
	private function _getEventProxy( listener, f : Function ) : Function
	{
		return Delegate.create.apply( Delegate, [ listener, f ].concat( arguments.splice( 2 ) ) );
	}
}